package net.jiastudy.biz.user.service.impl;

import java.util.List;
import java.util.Map;
import java.util.Set;

import net.jiastudy.biz.datasync.LeaderImporter;
import net.jiastudy.biz.datasync.UserImporter;
import net.jiastudy.biz.enums.DeptType;
import net.jiastudy.biz.enums.Gender;
import net.jiastudy.biz.sys.entity.Dept;
import net.jiastudy.biz.sys.service.DeptService;
import net.jiastudy.biz.user.entity.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import java.util.Date;
import org.springframework.data.domain.Sort;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;

import cn.hutool.core.util.StrUtil;
import net.jiastudy.biz.user.entity.User;
import net.jiastudy.biz.user.event.UserCreateEvent;
import net.jiastudy.biz.user.event.UserLoginEvent;
import net.jiastudy.biz.user.mapper.UserMapper;
import net.jiastudy.biz.user.service.RoleService;
import net.jiastudy.biz.user.service.UserService;
import net.jiastudy.core.base.BaseService;
import net.jiastudy.core.common.SysRole;
import net.jiastudy.core.common.validgroup.Create;
import net.jiastudy.core.common.validgroup.Update;
import net.jiastudy.core.exception.InvalidParameterException;
import net.jiastudy.core.exception.NotFoundException;
import net.jiastudy.core.exception.ServiceException;
import net.jiastudy.core.utils.BeanUtils;

@Service
public class UserServiceImpl extends BaseService<UserMapper, User> implements UserService {

	@Autowired
	private UserMapper userMapper;
	@Autowired
	private RoleService roleService;
	@Autowired
	private PasswordEncoder passwordEncoder;
	@Autowired
	private DeptService deptService;

	@Override
	public User getUserByName(String name) {
		User user = new User();
		user.setName(name);
		user = userMapper.selectOne(user);

		return user;
	}

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		User user = userMapper.getByUsername(username);
		if (null == user) {
			throw new UsernameNotFoundException("用户名或密码错误");
		}
		user.setAdmin(this.isAdmin(user.getId()));
		return user;
	}

	@Override
	public User getUserByUsername(String username) {
		User user = userMapper.getByUsername(username);
		if (null != user) {
			user.setAdmin(this.isAdmin(user.getId()));
		}
		return user;
	}

	@Override
	public User getUserById(Long id) {
		User user = userMapper.selectById(id);
		if (null != user) {
			user.setAdmin(this.isAdmin(user.getId()));
		}
		return user;
	}

	@Override
	public User createUser(@Validated(Create.class) User user) {
		if (this.checkUsernameExists(user.getUsername(), null)) {
			throw new ServiceException("406", "用户名已被占用");
		}
		String password = passwordEncoder.encode(user.getPassword());
		user.setPassword(password);
		if (retBool(userMapper.insert(user))) {
			Role role = roleService.getRoleByCode(SysRole.ROLE_USER.name());
			roleService.addUserRoles(user.getId(), role.getId());
			applicationEventPublisher.publishEvent(new UserCreateEvent(user, this.getCurrentUser()));
			return userMapper.selectById(user.getId());
		}
		return null;
	}

	@Override
	public User updateUser(@Validated(Update.class) User user) {
		User oldUser = userMapper.selectById(user.getId());
		if (null == oldUser) {
			throw new NotFoundException("用户不存在");
		}
		if (this.checkUsernameExists(user.getUsername(), user.getId())) {
			throw new ServiceException("406", "用户名已被占用");
		}
		BeanUtils.copyPropertiesWithIgnoreProperties(user, oldUser, "id", "password", "userType", "createDate",
				"lastModified");
		if (retBool(userMapper.updateById(oldUser))) {
			return userMapper.selectById(user.getId());
		}
		return null;
	}

	@Override
	public Set<String> findPermissionCodesByUserId(Long userId) {
		return roleService.findPermissionsByUserId(userId);
	}

	@Override
	public boolean checkUsernameExists(@Validated String username, Long currentUserId) {
		User user = userMapper.getByUsername(username);
		if (null == user) {
			return false;
		}
		if (user.getId().equals(currentUserId)) {
			return false;
		}
		return true;
	}

	@Override
	public boolean changePassword(Long userId, String oldPassword, String newPassword) {
		if (null == oldPassword || null == newPassword) {
			throw new InvalidParameterException("密码不能为空");
		}
		User user = userMapper.selectById(userId);
		if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
			throw new InvalidParameterException("旧密码不正确！");
		}
		user.setPassword(passwordEncoder.encode(newPassword));
		return retBool(userMapper.updateById(user));
	}

	@Override
	public boolean changePassword(Long userId, String newPassword) {
		User user = userMapper.selectById(userId);
		user.setPassword(passwordEncoder.encode(newPassword));
		return retBool(userMapper.updateById(user));
	}

	@Async
	@EventListener
	public void listenUserCreteEvent(UserCreateEvent createUserEvent) {
		User user = (User) createUserEvent.getSource();
		User createBy = (User) createUserEvent.getCurrentUser();
		if (null != createBy) {
			logger.debug("用户：" + user.getUsername() + "被创建，操作者：" + createBy.getUsername());
		}
	}

	@Async
	@EventListener
	public void listenUserCreteEvent(UserLoginEvent createLoginEvent) {
		User user = (User) createLoginEvent.getSource();
		logger.debug("用户：" + user.getUsername() + "登录了," + "登录IP:" + createLoginEvent.getLoginIp());
	}

	private boolean isAdmin(Long userId) {
		Set<String> roleCodes = roleService.findRoleCodesByUserId(userId);
		if (null == roleCodes) {
			return false;
		}
		return roleCodes.contains(SysRole.ROLE_SUPER_ADMIN.toString());
	}

	@Override
	public List<User> findUsersByIds(Set<Long> ids) {
		if (null == ids || ids.size() == 0) {
			return null;
		}
		return this.selectBatchIds(ids);
	}

	@Override
	public Page<User> pageUsers(Page<User> page, Map<String, String> conditions, Sort sort) {
		Wrapper<User> wrapper = new EntityWrapper<>();
		wrapper.eq(conditions.containsKey("deptId"), "dept_id", conditions.get("deptId"));
		if (conditions.containsKey("keywords") && StrUtil.isNotEmpty(conditions.get("keywords").trim())) {
			String keywords = conditions.get("keywords");
			wrapper.andNew().like("name", keywords).or().like("username", keywords).or().like("nickname", keywords);
		}

		if (conditions.containsKey("roleId") && StrUtil.isNotEmpty(conditions.get("roleId").trim())) {
			String roleId = conditions.get("roleId");
			Set<Long> userIds = roleService.findRoleUserIdsByRoleId(Long.parseLong(roleId));
			wrapper.andNew().in("id", userIds);
		}
		this.generateSort(wrapper, sort);
		page = this.selectPage(page, wrapper);
		List<User> users = page.getRecords();
		for (User user : users) {
			user.setRoles(roleService.findRolesByUserId(user.getId()));
		}
		return page;
	}

	@Override
	public boolean disableUser(Long id) {
		User user = this.selectById(id);
		user.setDisable(true);
		this.updateById(user);
		return true;
	}

	@Override
	public boolean enableUser(Long id) {
		User user = this.selectById(id);
		user.setDisable(false);
		this.updateById(user);
		return true;
	}

	@Override
	public void importUsers(List<UserImporter> list) {
		Role role = roleService.getRoleByCode(SysRole.ROLE_USER.name());
		for (UserImporter userImporter : list) {
			if (null != userImporter.getName() && null != userImporter.getNumber()) {
				User dbUser = getUserByUsername(userImporter.getNumber());

				Dept dbDept = deptService.getDeptByName(userImporter.getDeptName());
				Long deptId;
				if (null == dbDept) {
					Dept dept = new Dept();
					dept.setName(userImporter.getDeptName());
					dept.setType(DeptType.other);
					dept.setCode(String.valueOf(new Date().getTime()));
					dept = deptService.createDept(dept);
					deptId = dept.getId();
				} else {
					deptId = dbDept.getId();
				}

				if (null == dbUser) {
					User user = new User();
					user.setDeptId(deptId);

					user.setName(userImporter.getName());
					user.setUsername(userImporter.getNumber());

					user.setPassword(userImporter.getNumber());
					if (null != userImporter.getGender() && userImporter.getGender() == "男") {
						user.setGender(Gender.male);
					} else if (null != userImporter.getGender() && userImporter.getGender() == "女") {
						user.setGender(Gender.female);
					}
					user = createUser(user);
					roleService.addUserRoles(user.getId(), role.getId());
				} else {
					dbUser.setDeptId(deptId);
					updateUser(dbUser);
				}
			}
		}
	}

	@Override
	public void batchSetLeader(List<LeaderImporter> list) {
		Role role = roleService.getRoleByCode(SysRole.ROLE_DEPT_LEADER.toString());
		if (!list.isEmpty()) {
			for (LeaderImporter leaderImporter : list) {
				User user = getUserByUsername(leaderImporter.getNumber());
				if (null != user) {
					roleService.addUserRoles(user.getId(),role.getId());
				}
			}
		}
	}
}
